/*
 * Copyright 2019. Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.android.apps.santatracker.doodles.shared;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
import com.google.android.apps.santatracker.doodles.shared.actor.Actor;
import com.google.android.apps.santatracker.doodles.shared.physics.Util;
import java.util.HashMap;
import java.util.Map;
import org.json.JSONException;
import org.json.JSONObject;

/** An actor class which represents an arbitrarily-colored rectangle. */
public class ColoredRectangleActor extends Actor implements Touchable {
    /* Default color is black*/
    public static final String UNSPECIFIED = "unspecified";

    /* Golf colors */
    public static final String TEE_GREEN = "tee";
    public static final String FAIRWAY_GREEN = "fairway";

    /* Swimming colors */
    public static final String DISTANCE_30M = "30m";
    public static final String DISTANCE_50M = "50m";
    public static final String DISTANCE_100M = "100m";
    public static final String DISTANCE_LEVEL_LENGTH = "level length";
    public static final String DISTANCE_PR = "pr";
    public static final String STARTING_BLOCK = "start";

    public static final String DIMENS_X_KEY = "dimens x";
    public static final String DIMENS_Y_KEY = "dimens y";

    public static final Map<String, Integer> TYPE_TO_COLOR_MAP;

    static {
        TYPE_TO_COLOR_MAP = new HashMap<>();
        /* Golf */
        TYPE_TO_COLOR_MAP.put(TEE_GREEN, Constants.LIGHT_GREEN);
        TYPE_TO_COLOR_MAP.put(FAIRWAY_GREEN, Constants.DARK_GREEN);
        /* Swimming */
        TYPE_TO_COLOR_MAP.put(DISTANCE_30M, 0x44cd7f32);
        TYPE_TO_COLOR_MAP.put(DISTANCE_50M, 0x44c0c0c0);
        TYPE_TO_COLOR_MAP.put(DISTANCE_100M, 0x44ffd700);
        TYPE_TO_COLOR_MAP.put(DISTANCE_LEVEL_LENGTH, 0x44ffffff);
        TYPE_TO_COLOR_MAP.put(DISTANCE_PR, 0x4400cc00);
        TYPE_TO_COLOR_MAP.put(STARTING_BLOCK, 0xff4993a4);
        TYPE_TO_COLOR_MAP.put(UNSPECIFIED, 0xff000000);
    }

    public String type;
    public Vector2D dimens;
    private Direction selectedDirection;
    private Paint paint;
    private Paint midpointPaint;
    private Vector2D upMidpoint = Vector2D.get();
    private Vector2D downMidpoint = Vector2D.get();
    private Vector2D leftMidpoint = Vector2D.get();
    private Vector2D rightMidpoint = Vector2D.get();

    public ColoredRectangleActor(Vector2D position, Vector2D dimens) {
        this(position, dimens, UNSPECIFIED);
    }

    public ColoredRectangleActor(Vector2D position, Vector2D dimens, String type) {
        super(position, Vector2D.get());

        this.dimens = dimens;
        this.type = type;
        this.zIndex = -1;

        if (type.equals(FAIRWAY_GREEN)) {
            this.zIndex = -2;
        }

        selectedDirection = Direction.NONE;
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(TYPE_TO_COLOR_MAP.get(type));
        paint.setStyle(Style.FILL);

        midpointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        midpointPaint.setColor(Color.WHITE);

        updateExtents();
    }

    public static ColoredRectangleActor fromJSON(JSONObject json) throws JSONException {
        String type = json.getString(Actor.TYPE_KEY);
        Vector2D position =
                Vector2D.get((float) json.optDouble(X_KEY, 0), (float) json.optDouble(Y_KEY, 0));
        Vector2D dimens =
                Vector2D.get(
                        (float) json.optDouble(DIMENS_X_KEY, 0),
                        (float) json.optDouble(DIMENS_Y_KEY, 0));
        return new ColoredRectangleActor(position, dimens, type);
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawRect(
                position.x, position.y, position.x + dimens.x, position.y + dimens.y, paint);
    }

    public void setStyle(Style style) {
        paint.setStyle(style);
    }

    public void setStrokeWidth(float width) {
        paint.setStrokeWidth(width);
        paint.setStrokeCap(Cap.ROUND);
    }

    public void setColor(int color) {
        paint.setColor(color);
    }

    @Override
    public String getType() {
        return type;
    }

    @Override
    public boolean canHandleTouchAt(Vector2D worldCoords, float cameraScale) {
        Vector2D lowerRight = Vector2D.get(position).add(dimens);
        boolean retVal =
                Util.pointIsWithinBounds(position, lowerRight, worldCoords)
                        || worldCoords.distanceTo(upMidpoint) < Constants.SELECTION_RADIUS
                        || worldCoords.distanceTo(downMidpoint) < Constants.SELECTION_RADIUS
                        || worldCoords.distanceTo(leftMidpoint) < Constants.SELECTION_RADIUS
                        || worldCoords.distanceTo(rightMidpoint) < Constants.SELECTION_RADIUS;

        lowerRight.release();
        return retVal;
    }

    @Override
    public void startTouchAt(Vector2D worldCoords, float cameraScale) {
        if (worldCoords.distanceTo(upMidpoint) < Constants.SELECTION_RADIUS) {
            selectedDirection = Direction.UP;
        } else if (worldCoords.distanceTo(downMidpoint) < Constants.SELECTION_RADIUS) {
            selectedDirection = Direction.DOWN;
        } else if (worldCoords.distanceTo(leftMidpoint) < Constants.SELECTION_RADIUS) {
            selectedDirection = Direction.LEFT;
        } else if (worldCoords.distanceTo(rightMidpoint) < Constants.SELECTION_RADIUS) {
            selectedDirection = Direction.RIGHT;
        } else {
            selectedDirection = Direction.NONE;
        }
    }

    @Override
    public boolean handleMoveEvent(Vector2D delta) {
        if (selectedDirection == Direction.NONE) {
            position.subtract(delta);
        } else if (selectedDirection == Direction.UP) {
            position.y -= delta.y;
            dimens.y += delta.y;
        } else if (selectedDirection == Direction.DOWN) {
            dimens.y -= delta.y;
        } else if (selectedDirection == Direction.LEFT) {
            position.x -= delta.x;
            dimens.x += delta.x;
        } else {
            // Direction.RIGHT
            dimens.x -= delta.x;
        }
        updateExtents();
        return true;
    }

    @Override
    public boolean handleLongPress() {
        return false;
    }

    @Override
    public JSONObject toJSON() throws JSONException {
        JSONObject json = new JSONObject();
        json.put(TYPE_KEY, getType());
        json.put(X_KEY, position.x);
        json.put(Y_KEY, position.y);
        json.put(DIMENS_X_KEY, dimens.x);
        json.put(DIMENS_Y_KEY, dimens.y);
        return json;
    }

    private void updateExtents() {
        upMidpoint.set(position).add(dimens.x / 2, 0);
        downMidpoint.set(position).add(dimens.x / 2, dimens.y);
        leftMidpoint.set(position).add(0, dimens.y / 2);
        rightMidpoint.set(position).add(dimens.x, dimens.y / 2);
    }

    /** A direction used to pull the boundaries of the colored rectangle. */
    private enum Direction {
        NONE,
        UP,
        DOWN,
        LEFT,
        RIGHT,
    }
}
